package com.nf.health.app.datamain.activity;

import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.content.Context;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.widget.TextView;
import android.widget.Toast;

import com.afollestad.materialdialogs.DialogAction;
import com.afollestad.materialdialogs.MaterialDialog;
import com.android.volley.VolleyError;
import com.nf.health.app.BleThirdLib.BleManager;
import com.nf.health.app.BleThirdLib.conn.BleCharacterCallback;
import com.nf.health.app.BleThirdLib.conn.BleGattCallback;
import com.nf.health.app.BleThirdLib.exception.BleException;
import com.nf.health.app.BleThirdLib.utils.HexUtil;
import com.nf.health.app.activity.global.BaseActivity;
import com.nf.health.app.models.UserDeviceEntity;
import com.nf.health.app.utils.DeviceUUID;
import com.nf.health.app.utils.MaterialDialogManager;
import com.nf.health.app.utils.UserDeviceManager;


/**
 * Created by nf on 17/3/30.
 */

abstract public class MeasureBaseAcitivity extends BaseActivity {

    TextView tipsTextView;
    BleManager bleManager;
    Context context;
    public Handler handler = new Handler();
    private StringBuilder stringBuilder = new StringBuilder();

    public MaterialDialogManager mDialogManager;

    int handlerPostDelyTime = 300;//给蓝牙发命令的间隔时间

    int scanTimeCount;//扫描的次数

    int checkServiceCount;//发现服务失败,重新连接次数
    CheckServiceTimeCount serviceTimeCount;//检测服务是否失败,如果失败,就关掉蓝牙重新连接

    int checkBLECount;//检测蓝牙是否开启次数
    CheckBLEEnableTimeCount bleEnableTimeCount;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        context = this;
        initDefaultConfig();

        if (DEVICE_TYPE()!= DeviceUUID.HeartRateType ){

//            setContent(R.layout.activity_measure_base);
//
//            tipsTextView = (TextView) findViewById(R.id.tv_tips);
//            tipsTextView.setText("    \n     \n数据测量    \n    ");
//            tipsTextView.setOnClickListener(this);
//            tipsTextView.setOnLongClickListener(new View.OnLongClickListener() {
//                @Override
//                public boolean onLongClick(View v) {
//                    handler.post(new Runnable() {
//                        @Override
//                        public void run() {
//                            tipsTextView.setText(stringBuilder.toString());
//                        }
//                    });
//                    return  true;
//                }
//            });
        }

        bleManager = new BleManager(this);
        bleManager.enableBluetooth();
        serviceTimeCount = new CheckServiceTimeCount(5000, 1000);
        bleEnableTimeCount = new CheckBLEEnableTimeCount(7000, 1000);



    }

    protected void startMeasure(){
        mDialogManager = MaterialDialogManager.getInstance(MeasureBaseAcitivity.this);
        showDialog("提示", "正在寻找设备...");

        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                bleEnableTimeCount.start();
                new Thread(){
                    public void run(){
                        scanAndConnectToDevice();
                    }
                }.start();
            }
        }, handlerPostDelyTime * 3);
    }

    //扫描并连接设备
    protected void scanAndConnectToDevice() {

        if (DEVICE_TYPE() == DeviceUUID.HeartRateType){
            bleManager.scanNameAndConnect("HRM", 5000, false, new BleGattCallback() {
                @Override
                public void onServicesDiscovered(BluetoothGatt gatt, int status) {
                    setTipsText("\n第" + scanTimeCount + "次扫描" + " onServicesDiscovered" + "  status:" + status);
                    serviceDiscovered(gatt, status);
                }
                @Override
                public void onConnectSuccess(BluetoothGatt gatt, int status) {
                    setTipsText("\n第" + scanTimeCount + "次扫描" + " onConnectSuccess" + "  status:" + status);
                    ConnectSuccessDevice(gatt, status);
                }
                @Override
                public void onNotFoundDevice() {
                    setTipsText("\n第" + scanTimeCount + "次扫描" + " onNotFoundDevice");
                    //提示后重新扫描
                    bleEnableTimeCount.cancel();
                    connectFaildReconnect(scanTimeCount, "请确保小设备已开启,正在重新连接...");
                }
                @Override
                public void onConnectFailure(BleException exception) {
                    setTipsText("\n第" + scanTimeCount + "次扫描" + " onConnectFailure" + exception.toString());
                    //提示后重新扫描
                    connectFaildReconnect(scanTimeCount, "连接失败,正在重新连接...");
                }
                @Override
                public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
                    bleEnableTimeCount.cancel();
                    setTipsText("\n第" + scanTimeCount + "次扫描" + " onConnectionStateChange" + "  status:" + status + " newState:" + newState);
                }
            });
        }else {
            bleManager.scanMacAndConnect(MAC_ADRESS(), 5000, false, new BleGattCallback() {
                @Override
                public void onServicesDiscovered(BluetoothGatt gatt, int status) {
                    setTipsText("\n第" + scanTimeCount + "次扫描" + " onServicesDiscovered" + "  status:" + status);
                    serviceDiscovered(gatt, status);
                }
                @Override
                public void onConnectSuccess(BluetoothGatt gatt, int status) {
                    setTipsText("\n第" + scanTimeCount + "次扫描" + " onConnectSuccess" + "  status:" + status);
                    ConnectSuccessDevice(gatt, status);
                }
                @Override
                public void onNotFoundDevice() {
                    setTipsText("\n第" + scanTimeCount + "次扫描" + " onNotFoundDevice");
                    //提示后重新扫描
                    bleEnableTimeCount.cancel();
                    connectFaildReconnect(scanTimeCount, "请确保小设备已开启,正在重新连接...");
                }
                @Override
                public void onConnectFailure(BleException exception) {
                    setTipsText("\n第" + scanTimeCount + "次扫描" + " onConnectFailure" + exception.toString());
                    //提示后重新扫描
                    connectFaildReconnect(scanTimeCount, "连接失败,正在重新连接...");
                }
                @Override
                public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
                    bleEnableTimeCount.cancel();
                    setTipsText("\n第" + scanTimeCount + "次扫描" + " onConnectionStateChange" + "  status:" + status + " newState:" + newState);
                }
            });
        }

    }

    //设备连接成功 去发现服务
    //此时开始计时,2s内必须回调 发现服务成功,不然需要重新连接
    private void ConnectSuccessDevice(final BluetoothGatt gatt, int status) {
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {

                serviceTimeCount.start();
                showDialog("提示", "设备连接成功...");

                setTipsText("\n第" + scanTimeCount + "次扫描" + "ConnectSuccessDevice");
                gatt.discoverServices();
            }
        }, handlerPostDelyTime);
    }

    //服务被发现 --->  1,监听通知  2,写数据
    //此时开始计时 2s内必须回调通知监听成功
    private void serviceDiscovered(BluetoothGatt gatt, final int status) {
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {

                serviceTimeCount.cancel();
                showDialog("提示", "正在获取数据...");

                setTipsText("\n第" + scanTimeCount + "次扫描" + "notify_device()");
                notify_device();
                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        setTipsText("\n第" + scanTimeCount + "次扫描" + "write_device()");
                        if (sendOrder()){
                            write_device(sendOrderData());
                        }
                    }
                }, handlerPostDelyTime);
            }
        }, handlerPostDelyTime);
    }
    //写数据
    public void write_device(byte[] command) {
        bleManager.writeDevice(SERVICE_UUID(), WRITE_UUID(), command, new BleCharacterCallback() {
            @Override
            public void onSuccess(BluetoothGattCharacteristic characteristic) {
                serviceTimeCount.cancel();

                setTipsText("\n第"+scanTimeCount+"次扫描"+"write_device onsuccess"+ HexUtil.encodeHexStr(characteristic.getValue()));
            }

            @Override
            public void onFailure(BleException exception) {
                setTipsText("\n第 " + scanTimeCount+"次扫描"+"write_device onfailure" + exception.toString());
            }

        });
    }
    //监听通知
    private void notify_device() {
        bleManager.notify(SERVICE_UUID(), NOTIFY_UUID(), new BleCharacterCallback() {
            @Override
            public void onSuccess(BluetoothGattCharacteristic characteristic) {

                final byte[] receivedData = characteristic.getValue();
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        serviceTimeCount.cancel();

                        receivedDataAnalyse(receivedData);
                        if (DEVICE_TYPE() != DeviceUUID.PressureType){
                            setTipsText("\n接受到数据 notify_device onsuccess   " + HexUtil.encodeHexStr(receivedData));
                        }
                    }
                });
            }
            @Override
            public void onFailure(BleException exception) {
                setTipsText("\n第" + scanTimeCount + "次扫描" + "notify_device onFailure" + exception.toString());
            }
        });
    }
    //发现服务,监听通知过程中出现错误  ----> 取消所有连接重新开始连接
    private void connectFaildServiceReconnect() {

        if (++checkServiceCount >= 3) {
            if (mDialogManager != null){
                mDialogManager.showPositiveDialog("蓝牙错误", "请确定设别电量充足后重启小设备后再次连接", "再次连接", "取消", new MaterialDialogManager.PositiveDialogClickListener() {
                    @Override
                    public void onPositiveClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
                        scanTimeCount = 0;
                        checkServiceCount = 0;
                        connectFaildReconnect(0, "正在寻找设备...");
                    }

                    @Override
                    public void onNegativeClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
                        Toast.makeText(context, "错误,请退出界面,再次测量...", Toast.LENGTH_SHORT).show();
                        finish();
                    }
                });
            }
            return;
        }

        serviceTimeCount.cancel();
        showDialog("提示", "发现错误,正在重启蓝牙...");
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                bleManager.closeBluetoothGatt();
                bleManager.disableBluetooth();

                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        bleManager.enableBluetooth();

                        handler.postDelayed(new Runnable() {
                            @Override
                            public void run() {
                                scanTimeCount = 0;
                                connectFaildReconnect(scanTimeCount, "正在重新连接...");
                            }
                        }, handlerPostDelyTime * 3);
                    }
                }, handlerPostDelyTime * 2);
            }
        }, handlerPostDelyTime);

    }

    //第一二次连接失败后需要重新连接
    private void connectFaildReconnect(final int connectCount, final String showString) {

        setTipsText("\n第" + ++scanTimeCount + "次重新扫描 ");

        showDialog("提示", showString);
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {

                if (scanTimeCount < 3) {
                    handler.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            if (connectCount == 1) {
                                Toast.makeText(context, "请确定测量设备已经开启!", Toast.LENGTH_SHORT).show();
                            } else if (connectCount > 1) {

                                bleManager.closeBluetoothGatt();
                                bleManager.enableBluetooth();

                                Toast.makeText(context, "请确定测量设备已经开启,正在重试!", Toast.LENGTH_SHORT).show();
                            }
                            new Thread(){
                                public void run(){
                                    scanAndConnectToDevice();
                                }
                            }.start();
                        }
                    }, handlerPostDelyTime);
                } else {
                    //第三次扫描没有找到设备
                    if (mDialogManager != null){
                        mDialogManager.showPositiveDialog("未发现设备", "请确定设别电量充足后重启小设备后再次连接", "再次连接", "取消", new MaterialDialogManager.PositiveDialogClickListener() {
                            @Override
                            public void onPositiveClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
                                scanTimeCount = 0;
                                connectFaildReconnect(0, "正在寻找设备...");
                            }

                            @Override
                            public void onNegativeClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
                                Toast.makeText(context, "错误,请退出界面,再次测量...", Toast.LENGTH_SHORT).show();
                                finish();
                            }
                        });
                    }

                }
            }
        }, handlerPostDelyTime*5);

    }

    @Override
    public void finish() {
        super.finish();
    }

    @Override
    public void onBackPressed() {
        super.onBackPressed();
        finish();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
//        if (mDialogManager != null) {
            mDialogManager = null;
//            mDialogManager.hideAllDialog();
//        }
        serviceTimeCount.cancel();
        bleEnableTimeCount.cancel();
        bleManager.closeBluetoothGatt();
        bleManager.disableBluetooth();
    }

    public void showDialog(final String titleString, final String contentString) {

        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                if (mDialogManager != null ){
                    mDialogManager.showProgressDialog(titleString, contentString, false);
                }
            }
        });
    }

    private void setTipsText(final String string) {
        stringBuilder.append(string);
    }

    //定时器 在给定的时间内,如果设备还没有接受到数据 就需要进行异常处理
    public class CheckServiceTimeCount extends CountDownTimer {
        public CheckServiceTimeCount(long millisInFuture, long timecountInterval) {
            super(millisInFuture, timecountInterval);
        }

        @Override
        public void onTick(long l) {
            setTipsText("\n第" + scanTimeCount + "次倒计时  " + l / 1000);
        }

        @Override
        public void onFinish() {
            //如果 在固定的时间,没有发现服务,监听没有回调。就重启蓝牙,重新连接
            connectFaildServiceReconnect();
        }
    }

    //检测蓝牙是否正常开启
    private class CheckBLEEnableTimeCount extends CountDownTimer {
        public CheckBLEEnableTimeCount(long millisInFuture, long countDownInterval) {
            super(millisInFuture, countDownInterval);
        }

        @Override
        public void onTick(long l) {
            setTipsText("\n检测蓝牙是否开始倒计时" + l / 1000);
        }

        @Override
        public void onFinish() {

            if (checkBLECount++ < 2) {
                if (null == bleManager) {
                    bleManager = new BleManager(context);
                }
                if (!bleManager.isBlueEnable()){
                    bleManager.enableBluetooth();
                }

                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        bleEnableTimeCount.start();

                        new Thread(){
                            public void run(){
                                scanAndConnectToDevice();
                            }
                        }.start();
                    }
                }, handlerPostDelyTime * 3);
            } else {
                if (mDialogManager != null){
                    mDialogManager.showPositiveDialog("蓝牙错误", "请确定系统蓝牙已经开始", "再次连接", "取消", new MaterialDialogManager.PositiveDialogClickListener() {
                        @Override
                        public void onPositiveClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
                            new Thread(){
                                public void run(){
                                    scanAndConnectToDevice();
                                }
                            }.start();
                        }

                        @Override
                        public void onNegativeClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
                            Toast.makeText(context, "错误,请退出界面,再次测量...", Toast.LENGTH_SHORT).show();
                            finish();
                        }
                    });
                }

            }
        }
    }
    protected abstract void initDefaultConfig() ;//交给子类初始化
    protected abstract int DEVICE_TYPE() ;//数据测量的类型
    protected abstract byte[] sendOrderData() ; //发送给小设备的命令
    protected abstract void receivedDataAnalyse(byte[] data) ;//接受到数据,让子类处理
    protected abstract void upLoadMeasureFinishData() ;//上传测量完的数据

    private boolean sendOrder(){//是否需要发送开启命令数据
        int type = DEVICE_TYPE() ;
        boolean sendorder = true ;
        switch (type) {
            case DeviceUUID.UrineType:
            case DeviceUUID.OxygenType :
                sendorder = false;
                break;
            default:
                break;
        }
        return sendorder ;
    }

    private String MAC_ADRESS(){
        int type = DEVICE_TYPE() ;
        String macAdress ;
        switch (type){
            case DeviceUUID.OxygenType :
                UserDeviceEntity.OxygenDevice OxygenDevice = UserDeviceManager.getOxygenDevice(context);
                macAdress = OxygenDevice.getDeviceAdr();
                break;
            case DeviceUUID.PressureType :
                UserDeviceEntity.BloodPressDevice pressDevice = UserDeviceManager.getBloodPressDevice(context) ;
                macAdress = pressDevice.getDeviceAdr();
                break;
            case DeviceUUID.SugarType :
                UserDeviceEntity.BloodGlucosDevice SugarDevice = UserDeviceManager.getBloodGlucosDevice(context);
                macAdress = SugarDevice.getDeviceAdr();
                break;
            case DeviceUUID.TemperatureType :
                UserDeviceEntity.TemperatureDevice tempDevice = UserDeviceManager.getTemperatureDevice(context) ;
                macAdress = tempDevice.getDeviceAdr() ;
                break;
            case DeviceUUID.UrineType :
                UserDeviceEntity.UrinetestDevice urineDevice = UserDeviceManager.getUrinetestDevice(context);
                macAdress = urineDevice.getDeviceAdr() ;
                break;
            case DeviceUUID.BodyFatType:
                UserDeviceEntity.BloodBodyfatDevice fatDevice = UserDeviceManager.getBloodBodyfatDevice(context) ;
                macAdress = fatDevice.getDeviceAdr() ;
                break;
            default:
                macAdress = DeviceUUID.DEFAULT_UUID ;
                break;
        }
        return macAdress ;
    }
    private String SERVICE_UUID(){
        int type = DEVICE_TYPE() ;
        String UUID ;
        switch (type){
            case DeviceUUID.OxygenType :
                UUID = DeviceUUID.Oxygen.SERVICE_UUID ;
                break;
            case DeviceUUID.PressureType :
                UUID = DeviceUUID.Pressure.SERVICE_UUID ;
                break;
            case DeviceUUID.SugarType :
                UUID = DeviceUUID.Sugar.SERVICE_UUID ;
                break;
            case DeviceUUID.TemperatureType :
                UUID = DeviceUUID.Temperature.SERVICE_UUID ;
                break;
            case DeviceUUID.UrineType :
                UUID = DeviceUUID.Urine.SERVICE_UUID ;
                break;
            case DeviceUUID.BodyFatType :
                UUID = DeviceUUID.BodyFat.SERVICE_UUID ;
                break;
            case DeviceUUID.HeartRateType:
                UUID = DeviceUUID.HeartRate.SERVICE_UUID ;
                break;
            default:
                UUID = DeviceUUID.DEFAULT_UUID ;
                break;
        }
        return UUID ;

    }
    private String WRITE_UUID(){
        int type = DEVICE_TYPE() ;
        String UUID ;
        switch (type){
            case DeviceUUID.OxygenType :
                UUID = DeviceUUID.Oxygen.WRITE_UUID ;
                break;
            case DeviceUUID.PressureType :
                UUID = DeviceUUID.Pressure.WRITE_UUID ;
                break;
            case DeviceUUID.SugarType :
                UUID = DeviceUUID.Sugar.WRITE_UUID ;
                break;
            case DeviceUUID.TemperatureType :
                UUID = DeviceUUID.Temperature.WRITE_UUID ;
                break;
            case DeviceUUID.UrineType :
                UUID = DeviceUUID.Urine.WRITE_UUID ;
                break;
            case DeviceUUID.BodyFatType :
                UUID = DeviceUUID.BodyFat.WRITE_UUID ;
                break;
            case DeviceUUID.HeartRateType:
                UUID = DeviceUUID.HeartRate.WRITE_UUID ;
                break;
            default:
                UUID = DeviceUUID.DEFAULT_UUID ;
                break;
        }
        return UUID ;
    }
    private String NOTIFY_UUID(){
        int type = DEVICE_TYPE() ;
        String UUID ;
        switch (type){
            case DeviceUUID.OxygenType :
                UUID = DeviceUUID.Oxygen.NOTIFY_UUID ;
                break;
            case DeviceUUID.PressureType :
                UUID = DeviceUUID.Pressure.NOTIFY_UUID ;
                break;
            case DeviceUUID.SugarType :
                UUID = DeviceUUID.Sugar.NOTIFY_UUID ;
                break;
            case DeviceUUID.TemperatureType :
                UUID = DeviceUUID.Temperature.NOTIFY_UUID ;
                break;
            case DeviceUUID.UrineType :
                UUID = DeviceUUID.Urine.NOTIFY_UUID ;
                break;
            case DeviceUUID.BodyFatType :
                UUID = DeviceUUID.BodyFat.NOTIFY_UUID ;
                break;
            case DeviceUUID.HeartRateType:
                UUID = DeviceUUID.HeartRate.NOTIFY_UUID ;
                break;
            default:
                UUID = DeviceUUID.DEFAULT_UUID ;
                break;
        }
        return UUID ;
    }

    @Override
    public void handleActionSuccess(String actionName, Object object) {
        showToast("数据已上传到云端");
        finish();
    }

    @Override
    public void handleActionError(String actionName, String response, VolleyError error) {
        super.handleActionError(actionName, response, error);

        if (mDialogManager != null){
            mDialogManager.showPositiveDialog("提示","数据上传失败,是否从新上传数据,取消上传不会保存数据!","重新上传","不上传", new MaterialDialogManager.PositiveDialogClickListener() {
                @Override
                public void onPositiveClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
                    upLoadMeasureFinishData();
                }

                @Override
                public void onNegativeClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
                    showToast( "数据上传失败..." );
                    finish();
                }
            });
        }


    }
}
